home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / docindex.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  18.6 KB  |  844 lines

  1. /* docindex.c - Creates the window used by the document index in go and gimp.
  2.  *
  3.  * Copyright (C) 1998 Chris Lahey.
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  */
  15. #include "config.h"
  16.  
  17. #include <ctype.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21.  
  22. #include <gtk/gtk.h>
  23.  
  24. #include "dialog_handler.h"
  25. #include "docindex.h"
  26. #include "fileops.h"
  27. #include "gdisplay.h"
  28. #include "gimpimageP.h"
  29. #include "gimpui.h"
  30. #include "gimpdnd.h"
  31. #include "ops_buttons.h"
  32. #include "session.h"
  33.  
  34. #include "libgimp/gimpenv.h"
  35.  
  36. #include "libgimp/gimpintl.h"
  37.  
  38. #include "pixmaps/folder.xpm"
  39. #include "pixmaps/raise.xpm"
  40. #include "pixmaps/lower.xpm"
  41. #include "pixmaps/delete.xpm"
  42.  
  43.  
  44. typedef struct
  45. {
  46.   GtkWidget *window;
  47.   GtkWidget *list;
  48. } IdeaManager;
  49.  
  50. typedef struct
  51. {
  52.   gboolean  boole;
  53.   gchar    *string;
  54.   gpointer  data;
  55. } BoolCharPair;
  56.  
  57.  
  58. /*  forward declarations  */
  59.  
  60. static void      create_idea_list                  (void);
  61. static void      idea_add_in_position              (gchar       *label,
  62.                             gint         position);
  63. static void      open_idea_window                  (void);
  64. static void      open_or_raise                     (gchar       *file_name,
  65.                             gboolean    try_raise);
  66.  
  67. static void      idea_open_callback                (GtkWidget   *widget,
  68.                             gpointer     data);
  69. static void      idea_open_or_raise_callback       (GtkWidget   *widget,
  70.                             gpointer     data);
  71. static void      idea_up_callback                  (GtkWidget   *widget,
  72.                             gpointer     data);
  73. static void      idea_to_top_callback              (GtkWidget   *widget,
  74.                             gpointer     data);
  75. static void      idea_down_callback                (GtkWidget   *widget,
  76.                             gpointer     data);
  77. static void      idea_to_bottom_callback           (GtkWidget   *widget,
  78.                             gpointer     data);
  79. static void      idea_remove_callback              (GtkWidget   *widget,
  80.                             gpointer     data);
  81. static void      idea_hide_callback                (GtkWidget   *widget,
  82.                             gpointer     data);
  83.  
  84. static void      load_idea_manager                 (IdeaManager *ideas);
  85. static void      save_idea_manager                 (IdeaManager *ideas);
  86.  
  87.  
  88. /*  local variables  */
  89.  
  90. static IdeaManager *ideas     = NULL;
  91. static GList       *idea_list = NULL;
  92.  
  93. /*  the ops buttons  */
  94. static GtkSignalFunc open_ext_callbacks[] = 
  95. {
  96.   idea_open_or_raise_callback, file_open_callback, NULL, NULL
  97. };
  98.  
  99. static GtkSignalFunc raise_ext_callbacks[] = 
  100. {
  101.   idea_to_top_callback, NULL, NULL, NULL
  102. };
  103.  
  104. static GtkSignalFunc lower_ext_callbacks[] = 
  105. {
  106.   idea_to_bottom_callback, NULL, NULL, NULL
  107. };
  108.  
  109. static OpsButton ops_buttons[] =
  110. {
  111.   { folder_xpm, idea_open_callback, open_ext_callbacks,
  112.     N_("Open the selected entry\n"
  113.        "<Shift> Raise window if already open\n"
  114.        "<Ctrl> Load Image dialog"), NULL,
  115.     NULL, 0 },
  116.   { raise_xpm, idea_up_callback, raise_ext_callbacks,
  117.     N_("Move the selected entry up in the index\n"
  118.        "<Shift> To top"), NULL,
  119.     NULL, 0 },
  120.   { lower_xpm, idea_down_callback, lower_ext_callbacks,
  121.     N_("Move the selected entry down in the index\n"
  122.        "<Shift> To bottom"), NULL,
  123.     NULL, 0 },
  124.   { delete_xpm, idea_remove_callback, NULL,
  125.     N_("Remove the selected entry from the index"), NULL,
  126.     NULL, 0 },
  127.   { NULL, NULL, NULL, NULL, NULL, NULL, 0 }
  128. };
  129.  
  130.  
  131. /*  dnd stuff  */
  132.  
  133. static GtkTargetEntry drag_types[] =
  134. {
  135.   GIMP_TARGET_URI_LIST,
  136.   GIMP_TARGET_TEXT_PLAIN,
  137.   GIMP_TARGET_NETSCAPE_URL
  138. };
  139. static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
  140.  
  141.  
  142. /*  public functions  */
  143.  
  144. void
  145. document_index_create (void)
  146. {
  147.   if (ideas)
  148.     gdk_window_raise (ideas->window->window);
  149.   else
  150.     open_idea_window ();
  151. }
  152.  
  153. void
  154. document_index_free (void)
  155. {
  156.   idea_hide_callback (NULL, NULL);
  157. }
  158.  
  159. void
  160. document_index_add (gchar *title)
  161. {
  162.   idea_add_in_position (title, 0);
  163. }
  164.  
  165. FILE *
  166. document_index_parse_init (void)
  167. {
  168.   FILE  *fp;
  169.   gchar *desktopfile;
  170.   gint   dummy;
  171.  
  172.   desktopfile = gimp_personal_rc_file ("ideas");
  173.  
  174.   fp = fopen (desktopfile, "r");
  175.  
  176.   if (fp != NULL)
  177.     {
  178.       /*  eventually strip away the old file format's first line  */
  179.       if (fscanf (fp, "%i %i %i %i", &dummy, &dummy, &dummy, &dummy) != 4)
  180.     {
  181.       fclose (fp);
  182.       fp = fopen (desktopfile, "r");
  183.     }
  184.     }
  185.  
  186.   g_free (desktopfile);
  187.  
  188.   return fp;
  189. }
  190.  
  191. gchar *
  192. document_index_parse_line (FILE * fp)
  193. {
  194.   gint  n, len;
  195.   gchar buf[4096];
  196.  
  197.   while (fgets (buf, sizeof (buf), fp))
  198.     {
  199.       len = n = 0;
  200.       sscanf (buf, "%d %n", &len, &n);
  201.       if (len > 0 && n < strlen (buf))
  202.         return g_strndup (buf + n, len);
  203.     }
  204.  
  205.   return NULL;
  206. }
  207.  
  208.  
  209. /*  local functions  */
  210.  
  211. static void
  212. load_from_list (gpointer data,
  213.         gpointer data_null)
  214. {
  215.   idea_add_in_position ((gchar *) data, -1);
  216. }
  217.  
  218. static void
  219. load_idea_manager (IdeaManager *ideas)
  220. {
  221.   FILE *fp = NULL;
  222.  
  223.   if (! idea_list)
  224.     fp = document_index_parse_init ();
  225.  
  226.   if (idea_list || fp)
  227.     {
  228.       gtk_widget_show (ideas->window);
  229.  
  230.       if (fp)
  231.     {
  232.       gchar *title;
  233.  
  234.       while ((title = document_index_parse_line (fp)))
  235.         {
  236.           idea_add_in_position (title, -1);
  237.           g_free (title);
  238.         }
  239.       fclose (fp);
  240.     }
  241.       else
  242.     {
  243.       g_list_foreach (idea_list, load_from_list, NULL);
  244.       g_list_foreach (idea_list, (GFunc) g_free, NULL);
  245.       g_list_free (idea_list);
  246.       idea_list = 0;
  247.     }
  248.     }
  249.   else
  250.     {
  251.       gtk_widget_show (ideas->window);
  252.     }
  253. }
  254.  
  255. static void
  256. save_to_ideas (gpointer data,
  257.            gpointer user_data)
  258. {
  259.   gchar *title;
  260.  
  261.   title = GTK_LABEL (GTK_BIN (data)->child)->label;
  262. #ifdef GDK_USE_UTF8_MBS
  263.   title = g_filename_from_utf8 (title, -1, NULL, NULL, NULL);
  264. #endif
  265.   fprintf ((FILE *) user_data, "%d %s\n", strlen (title), title);
  266. #ifdef GDK_USE_UTF8_MBS
  267.   g_free (title);
  268. #endif
  269. }
  270.  
  271. static void
  272. save_list_to_ideas (gpointer data,
  273.             gpointer user_data)
  274. {
  275.   gchar *title;
  276.  
  277.   title = (gchar *) data;
  278.  
  279.   fprintf ((FILE *) user_data, "%d %s\n", (int) strlen (title), title);
  280. }
  281.  
  282. static void
  283. save_idea_manager (IdeaManager *ideas)
  284. {
  285.   FILE  *fp;
  286.   gchar *desktopfile;
  287.     
  288.   /* open persistant desktop file. */
  289.   desktopfile = gimp_personal_rc_file ("ideas");
  290.   fp = fopen (desktopfile, "w");
  291.   g_free (desktopfile);
  292.  
  293.   if (fp)
  294.     {
  295.       if (ideas)
  296.     {
  297.       g_list_foreach (GTK_LIST (ideas->list)->children, save_to_ideas, fp);
  298.     }
  299.       else if (idea_list)
  300.     {
  301.       g_list_foreach (idea_list, save_list_to_ideas, fp);
  302.     }
  303.  
  304.       fclose (fp);
  305.     }
  306. }
  307.  
  308. static void
  309. save_to_list (gpointer data,
  310.           gpointer null_data)
  311. {
  312.   gchar *title;
  313.  
  314.   title = g_strdup (GTK_LABEL (GTK_BIN (data)->child)->label);
  315. #ifdef GDK_USE_UTF8_MBS
  316.   {
  317.     gchar *tmp = title;
  318.     title = g_filename_from_utf8 (title, -1, NULL, NULL, NULL);
  319.     g_free (tmp);
  320.   }
  321. #endif
  322.   idea_list = g_list_append (idea_list, title);
  323. }
  324.  
  325. static void
  326. create_idea_list (void)
  327. {
  328.   if (idea_list)
  329.     {
  330.       g_list_foreach (idea_list, (GFunc) g_free, NULL);
  331.       g_list_free (idea_list);
  332.       idea_list = 0;
  333.     }
  334.  
  335.   g_list_foreach (GTK_LIST (ideas->list)->children, save_to_list, NULL);
  336. }
  337.  
  338. static gint
  339. list_item_callback (GtkWidget      *widget,
  340.             GdkEventButton *event,
  341.             gpointer        data)
  342. {
  343.   if (GTK_IS_LIST_ITEM (widget) &&
  344.       event->type == GDK_2BUTTON_PRESS)
  345.     {
  346.       gchar *label = GTK_LABEL (GTK_BIN (widget)->child)->label;
  347. #ifdef GDK_USE_UTF8_MBS
  348.       label = g_filename_from_utf8 (label, -1, NULL, NULL, NULL);
  349. #endif
  350.       open_or_raise (label, FALSE);
  351. #ifdef GDK_USE_UTF8_MBS
  352.       g_free (label);
  353. #endif
  354.     }
  355.  
  356.   return FALSE;
  357.  
  358. static void
  359. check_needed (gpointer data,
  360.           gpointer user_data)
  361. {
  362.   BoolCharPair *pair;
  363.   gchar *label;
  364.  
  365.   pair = (BoolCharPair *) user_data;
  366.   label = GTK_LABEL (GTK_BIN (data)->child)->label;
  367. #ifdef GDK_USE_UTF8_MBS
  368.   label = g_filename_from_utf8 (label, -1, NULL, NULL, NULL);
  369. #endif
  370.   if (strcmp (pair->string, label) == 0)
  371.     {
  372.       pair->boole = TRUE;
  373.       pair->data  = data;
  374.     }
  375. #ifdef GDK_USE_UTF8_MBS
  376.   g_free (label);
  377. #endif
  378. }
  379.  
  380. static void
  381. check_needed_list (gpointer data,
  382.            gpointer user_data)
  383. {
  384.   BoolCharPair *pair;
  385.  
  386.   pair = (BoolCharPair *) user_data;
  387.  
  388.   if (strcmp (pair->string, (gchar *) data) == 0)
  389.     {
  390.       pair->boole = TRUE;
  391.       pair->data  = data;
  392.     }
  393. }
  394.  
  395. static void
  396. idea_add_in_position_with_select (gchar    *title,
  397.                   gint      position,
  398.                   gboolean  select)
  399. {
  400.   BoolCharPair  pair;
  401.  
  402. #ifdef GDK_USE_UTF8_MBS
  403.   gchar *utf8_title = g_filename_to_utf8 (title, -1, NULL, NULL, NULL);
  404. #endif
  405.  
  406.   pair.boole  = FALSE;
  407.   pair.string = title;
  408.   pair.data   = NULL;
  409.  
  410.   if (ideas)
  411.     {
  412.       g_list_foreach (GTK_LIST (ideas->list)->children, check_needed, &pair);
  413.  
  414.       if (! pair.boole)
  415.     {
  416.       GtkWidget *listitem;
  417.       GList     *list = NULL;
  418.  
  419. #ifdef GDK_USE_UTF8_MBS
  420.       listitem = gtk_list_item_new_with_label (utf8_title);
  421. #else
  422.       listitem = gtk_list_item_new_with_label (title);
  423. #endif
  424.       list = g_list_append (list, listitem);
  425.  
  426.       if (position < 0)
  427.         gtk_list_append_items (GTK_LIST (ideas->list), list);
  428.       else
  429.         gtk_list_insert_items (GTK_LIST (ideas->list), list, position);
  430.  
  431.       gtk_signal_connect (GTK_OBJECT (listitem), "button_press_event",
  432.                   GTK_SIGNAL_FUNC (list_item_callback),
  433.                   NULL);
  434.  
  435.       gtk_widget_show (listitem);
  436.  
  437.       if (select)
  438.         gtk_list_item_select (GTK_LIST_ITEM  (listitem));
  439.     }
  440.       else /* move entry to top */
  441.     {
  442.       gchar *title = g_strdup (GTK_LABEL (GTK_BIN (pair.data)->child)->label);
  443. #ifdef GDK_USE_UTF8_MBS
  444.       {
  445.         gchar *tmp = title;
  446.         title = g_filename_from_utf8 (title, -1, NULL, NULL, NULL);
  447.         g_free (tmp);
  448.       }
  449. #endif
  450.       gtk_container_remove (GTK_CONTAINER (ideas->list),
  451.                 GTK_WIDGET (pair.data));
  452.       idea_add_in_position_with_select (title, 0, TRUE);
  453.       g_free (title); 
  454.     }
  455.     }
  456.   else
  457.     {
  458.       if (! idea_list)
  459.     {
  460.       FILE  *fp;
  461.  
  462.       fp = document_index_parse_init ();
  463.  
  464.       if (fp)
  465.         {  
  466.           gchar *filename;
  467.  
  468.           while ((filename = document_index_parse_line (fp)))
  469.         {
  470.           idea_list = g_list_append (idea_list, g_strdup (filename));
  471.           g_free (filename);
  472.         }
  473.  
  474.           fclose (fp);
  475.         }
  476.     }
  477.  
  478.       g_list_foreach (idea_list, check_needed_list, &pair);
  479.  
  480.       if (! pair.boole)
  481.     {
  482.       if (position < 0)
  483.         idea_list = g_list_prepend (idea_list, g_strdup (title));
  484.       else
  485.         idea_list = g_list_insert (idea_list, g_strdup (title), position);
  486.     }
  487.       else /* move entry to top */
  488.     {
  489.       idea_list = g_list_remove (idea_list, pair.data);
  490.       g_free (pair.data);
  491.       idea_list = g_list_prepend (idea_list, g_strdup (title));
  492.     }
  493.     }
  494. }
  495.  
  496. static void
  497. idea_add_in_position (gchar *title,
  498.               gint   position)
  499. {
  500.   idea_add_in_position_with_select (title, position, TRUE);
  501. }
  502.  
  503. static void
  504. raise_if_match (gpointer data,
  505.         gpointer user_data)
  506. {
  507.   GDisplay     *gdisp;
  508.   BoolCharPair *pair;
  509.  
  510.   gdisp = (GDisplay *) data;
  511.   pair  = (BoolCharPair *) user_data;
  512.  
  513.   if (gdisp->gimage->has_filename &&
  514.       strcmp (pair->string, gdisp->gimage->filename) == 0)
  515.     {
  516.       pair->boole = TRUE;
  517.       gdk_window_raise (gdisp->shell->window);
  518.     }
  519. }
  520.  
  521. static void
  522. open_or_raise (gchar    *file_name,
  523.            gboolean  try_raise)
  524. {
  525.   BoolCharPair pair;
  526.  
  527.   pair.boole  = FALSE;
  528.   pair.string = file_name;
  529.   pair.data   = NULL;
  530.  
  531.   if (try_raise)
  532.     {
  533.       gdisplays_foreach (raise_if_match, &pair);
  534.  
  535.       if (! pair.boole)
  536.     {
  537.       file_open (file_name, file_name);
  538.     }
  539.     }
  540.   else
  541.     {
  542.       file_open (file_name, file_name);
  543.     }
  544. }
  545.  
  546.  
  547. /*  toolbar / dialog callbacks  */
  548.  
  549. static gint
  550. idea_move (GtkWidget *widget,
  551.        gint       distance,
  552.        gboolean   select)
  553. {
  554.   gint   orig_position;
  555.   gint   position;
  556.   gchar *title;
  557.  
  558.   orig_position = g_list_index (GTK_LIST (ideas->list)->children, widget);
  559.   position = orig_position + distance;
  560.  
  561.   if (position < 0)
  562.     position = 0;
  563.  
  564.   if (position >= g_list_length (GTK_LIST (ideas->list)->children))
  565.     position = g_list_length (GTK_LIST (ideas->list)->children) - 1;
  566.  
  567.   if (position != orig_position)
  568.     {
  569.       title = g_strdup (GTK_LABEL (GTK_BIN (widget)->child)->label);
  570. #ifdef GDK_USE_UTF8_MBS
  571.       {
  572.     gchar *tmp = title;
  573.     title = g_filename_from_utf8 (title, -1, NULL, NULL, NULL);
  574.     g_free (tmp);
  575.       }
  576. #endif
  577.       gtk_container_remove (GTK_CONTAINER (ideas->list), widget);
  578.       idea_add_in_position_with_select (title, position, select);
  579.       g_free (title); 
  580.    }
  581.  
  582.   return position - orig_position;
  583. }
  584.  
  585. static void
  586. idea_open_callback (GtkWidget   *widget,
  587.             gpointer     data)
  588. {
  589.   GtkWidget *selected;
  590.   gchar *label;
  591.  
  592.   if (GTK_LIST (ideas->list)->selection)
  593.     {
  594.       selected = GTK_LIST (ideas->list)->selection->data;
  595.       label = GTK_LABEL (GTK_BIN (selected)->child)->label;
  596. #ifdef GDK_USE_UTF8_MBS
  597.       label = g_filename_from_utf8 (label, -1, NULL, NULL, NULL);
  598. #endif
  599.       open_or_raise (label, FALSE);
  600. #ifdef GDK_USE_UTF8_MBS
  601.       g_free (label);
  602. #endif
  603.     }
  604.   else
  605.     {
  606.       file_open_callback (widget, data);
  607.     }
  608. }
  609.  
  610. static void
  611. idea_open_or_raise_callback (GtkWidget   *widget,
  612.                  gpointer     data)
  613. {
  614.   GtkWidget *selected;
  615.   gchar *label;
  616.  
  617.   if (GTK_LIST (ideas->list)->selection)
  618.     {
  619.       selected = GTK_LIST (ideas->list)->selection->data;
  620.       label = GTK_LABEL (GTK_BIN (selected)->child)->label;
  621. #ifdef GDK_USE_UTF8_MBS
  622.       label = g_filename_from_utf8 (label, -1, NULL, NULL, NULL);
  623. #endif
  624.       open_or_raise (label, TRUE);
  625. #ifdef GDK_USE_UTF8_MBS
  626.       g_free (label);
  627. #endif
  628.     }
  629.   else
  630.     {
  631.       file_open_callback (widget, data);
  632.     }
  633. }
  634.  
  635. static void
  636. idea_up_callback (GtkWidget *widget,
  637.           gpointer   data)
  638. {
  639.   GtkWidget *selected;
  640.  
  641.   if (GTK_LIST (ideas->list)->selection)
  642.     {
  643.       selected = GTK_LIST (ideas->list)->selection->data;
  644.       idea_move (selected, -1, TRUE);
  645.     }
  646. }
  647.  
  648. static void
  649. idea_to_top_callback (GtkWidget   *widget,
  650.               gpointer     data)
  651. {
  652.   GtkWidget *selected;
  653.  
  654.   if (GTK_LIST (ideas->list)->selection)
  655.     {
  656.       selected = GTK_LIST (ideas->list)->selection->data;
  657.       idea_move (selected, - g_list_length (GTK_LIST (ideas->list)->children),
  658.          TRUE);
  659.     }
  660. }
  661.  
  662. static void
  663. idea_down_callback (GtkWidget *widget,
  664.             gpointer   data)
  665. {
  666.   GtkWidget *selected;
  667.  
  668.   if (GTK_LIST (ideas->list)->selection)
  669.     {
  670.       selected = GTK_LIST (ideas->list)->selection->data;
  671.       idea_move (selected, 1, TRUE);
  672.     }
  673. }
  674.  
  675. static void
  676. idea_to_bottom_callback (GtkWidget   *widget,
  677.              gpointer     data)
  678. {
  679.   GtkWidget *selected;
  680.  
  681.   if (GTK_LIST (ideas->list)->selection)
  682.     {
  683.       selected = GTK_LIST (ideas->list)->selection->data;
  684.       idea_move (selected, g_list_length (GTK_LIST (ideas->list)->children),
  685.          TRUE);
  686.     }
  687. }
  688.  
  689. static void
  690. idea_remove (GtkWidget *widget)
  691. {
  692.   gint position;
  693.  
  694.   position = g_list_index (GTK_LIST (ideas->list)->children, widget);
  695.  
  696.   gtk_container_remove (GTK_CONTAINER (ideas->list), widget);
  697.  
  698.   if (g_list_length (GTK_LIST (ideas->list)->children) - 1 < position)
  699.     position = g_list_length (GTK_LIST (ideas->list)->children) - 1;
  700.  
  701.   gtk_list_select_item (GTK_LIST (ideas->list), position);  
  702. }
  703.  
  704. static void
  705. idea_remove_callback (GtkWidget *widget,
  706.               gpointer   data)
  707. {
  708.   GtkWidget *selected;
  709.  
  710.   if (GTK_LIST (ideas->list)->selection)
  711.     {
  712.       selected = GTK_LIST (ideas->list)->selection->data;
  713.       idea_remove (selected);
  714.     }
  715. }
  716.  
  717. static void
  718. idea_hide_callback (GtkWidget *widget,
  719.             gpointer   data)
  720. {
  721.   if (ideas || idea_list)
  722.     save_idea_manager (ideas);
  723.  
  724.   /* False if exiting */
  725.   if (ideas)
  726.     {
  727.       create_idea_list ();
  728.       dialog_unregister (ideas->window);
  729.       session_get_window_info (ideas->window, &document_index_session_info);
  730.       gtk_widget_destroy (ideas->window);
  731.       g_free (ideas);
  732.       ideas = 0;
  733.     }
  734. }
  735.  
  736. static void
  737. ops_buttons_update (GtkWidget *widget,
  738.             gpointer   data)
  739. {
  740.   GtkWidget *selected = NULL;
  741.   gint       length   = 0;
  742.   gint       index    = -1;
  743.  
  744.   length = g_list_length (GTK_LIST (ideas->list)->children);
  745.  
  746.   if (GTK_LIST (ideas->list)->selection)
  747.     {
  748.       selected = GTK_LIST (ideas->list)->selection->data;
  749.       index  = g_list_index  (GTK_LIST (ideas->list)->children, selected);
  750.     }
  751.  
  752. #define SET_OPS_SENSITIVE(button,condition) \
  753.         gtk_widget_set_sensitive (ops_buttons[(button)].widget, \
  754.                                   (condition) != 0)
  755.  
  756.   SET_OPS_SENSITIVE (1, selected && index > 0);
  757.   SET_OPS_SENSITIVE (2, selected && index < (length - 1));
  758.   SET_OPS_SENSITIVE (3, selected);
  759.  
  760. #undef SET_OPS_SENSITIVE
  761. }
  762.  
  763. static void
  764. open_idea_window (void)
  765. {
  766.   GtkWidget *main_vbox;
  767.   GtkWidget *scrolled_win;
  768.   GtkWidget *abox;
  769.   GtkWidget *button_box;
  770.   gint       i;
  771.  
  772.   ideas = g_new0 (IdeaManager, 1);
  773.  
  774.   ideas->window = gimp_dialog_new (_("Document Index"), "docindex",
  775.                    gimp_standard_help_func,
  776.                    "dialogs/document_index.html",
  777.                    GTK_WIN_POS_MOUSE,
  778.                    FALSE, TRUE, FALSE,
  779.  
  780.                    _("Close"), idea_hide_callback,
  781.                    NULL, NULL, NULL, TRUE, TRUE,
  782.  
  783.                    NULL);
  784.  
  785.   gtk_drag_dest_set (ideas->window,
  786.                      GTK_DEST_DEFAULT_ALL,
  787.                      drag_types, n_drag_types,
  788.                      GDK_ACTION_COPY);
  789.  
  790.   gimp_dnd_file_dest_set (ideas->window);
  791.  
  792.   dialog_register (ideas->window);
  793.   session_set_window_geometry (ideas->window, &document_index_session_info,
  794.                    TRUE);
  795.  
  796.   main_vbox = gtk_vbox_new (FALSE, 4);
  797.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4);
  798.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (ideas->window)->vbox),
  799.              main_vbox);
  800.   gtk_widget_show (main_vbox);
  801.  
  802.   /* Scrolled window */
  803.   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  804.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  805.                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
  806.   gtk_box_pack_start (GTK_BOX (main_vbox), scrolled_win, TRUE, TRUE, 0); 
  807.   gtk_widget_show (scrolled_win);
  808.  
  809.   /* Setup list */
  810.   ideas->list = gtk_list_new ();
  811.   gtk_list_set_selection_mode (GTK_LIST (ideas->list), GTK_SELECTION_BROWSE);
  812.   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win),
  813.                      ideas->list);
  814.   gtk_widget_show (ideas->list);
  815.  
  816.   /*  The ops buttons  */
  817.   abox = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
  818.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ideas->window)->action_area), abox,
  819.               FALSE, FALSE, 4);
  820.   gtk_widget_show (abox);
  821.  
  822.   button_box = ops_button_box_new (ops_buttons, OPS_BUTTON_NORMAL);
  823.   gtk_container_add (GTK_CONTAINER (abox), button_box);
  824.   gtk_widget_show (button_box);
  825.  
  826.   for (i = 0; ; i++)
  827.     {
  828.       if (ops_buttons[i].widget == NULL)
  829.     break;
  830.  
  831.       gtk_misc_set_padding (GTK_MISC (GTK_BIN (ops_buttons[i].widget)->child),
  832.                 12, 0);
  833.     }
  834.  
  835.   /* Load and Show window */
  836.   load_idea_manager (ideas);
  837.  
  838.   gtk_signal_connect_after (GTK_OBJECT (ideas->list), "selection_changed",
  839.                 GTK_SIGNAL_FUNC (ops_buttons_update),
  840.                 NULL);
  841.   ops_buttons_update (NULL, NULL);
  842. }
  843.